package com.lvcoding.secdemo1.config;

import com.lvcoding.secdemo1.security.KaptchaFilter;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

/**
 * @description 描述
 * @date 2022-02-06 下午9:25
 * @author wuyanshen
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Bean
	public UserDetailsService userDetailsService() {
		InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
		inMemoryUserDetailsManager
				.createUser(User.withUsername("root").password("{noop}123").roles("superadmin").build());
		return inMemoryUserDetailsManager;
	}

	// /**
	// * Springboot默认的全局AuthenticationManager，它会自动在Spring工厂中去找UserDetailService自定义实例，
	// * 只要有就自动设置为数据源
	// * @param authenticationManagerBuilder
	// */
	// @Autowired
	// public void test(AuthenticationManagerBuilder authenticationManagerBuilder) {
	// System.out.println("authenticationManagerBuilder = " +
	// authenticationManagerBuilder);
	// }

	/**
	 * 1.自定义全局AuthenticationManager的时候，它就会覆盖Spring工厂中默认的全局AuthenticationManager.
	 * 2.springboot不会在Spring工厂中去找UserDetailService自定义实例，需要显式的指定UserDetailService实例，然后将它设置为数据源，
	 * 3.这种自定义方式创建的AuthenticationManager是一个工厂内部本地的AuthenticationManager（相当于在工厂内new了一个，不能在外部使用），也就是它不允许在其他组件中注入
	 *
	 * 但是还是推荐使用这种方式，这种自定义的方式更加灵活
	 * @param auth
	 * @throws Exception
	 */
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		System.out.println("auth = " + auth);
		auth.userDetailsService(userDetailsService());
	}

	/**
	 * 作用：用来将自定义的“本地的”AuthenticationManager在Spring工厂中暴露出来，供其他组件注入AuthenticationManager
	 *
	 * 说明： 使用@Bean注解让AuthenticationManager成为Spring工厂的一个组件供其他组件注入
	 * @return
	 * @throws Exception
	 */
	@Bean
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

	@Bean
	public KaptchaFilter kaptchaFilter() throws Exception {
		KaptchaFilter kaptchaFilter = new KaptchaFilter();
		kaptchaFilter.setFilterProcessesUrl("/doLogin");
		kaptchaFilter.setKaptchaParameter("kaptcha");
		kaptchaFilter.setAuthenticationManager(authenticationManagerBean());
		return kaptchaFilter;
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.addFilterAt(kaptchaFilter(), UsernamePasswordAuthenticationFilter.class);
		http.authorizeRequests().mvcMatchers("/login.html", "/index", "/kaptcha").permitAll().anyRequest()
				.authenticated().and().formLogin().loginPage("/login.html") // 一旦自定义了登录页面，就必须指定登录的url
				.loginProcessingUrl("/doLogin") // 指定登录的url
				.successForwardUrl("/index") // forward跳转，不会跳转到之前的请求路径
				// .defaultSuccessUrl("/index") // redirect跳转，会跳转到请求之前保存的请求路径
				.failureUrl("/login.html").and().csrf().disable();

	}

}
